package com.test.netty;

import com.alibaba.fastjson.JSONObject;
import com.sun.tools.doclets.internal.toolkit.Content;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.CharsetUtil;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;

public class NettyEchoServer {

    private void response(ChannelHandlerContext ctx, Content c) {

        // 1.设置响应
        FullHttpResponse resp = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                HttpResponseStatus.OK,
                Unpooled.copiedBuffer(JSONObject.toJSONString(c), CharsetUtil.UTF_8));

        resp.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");

        // 2.发送
        // 注意必须在使用完之后，close channel
        ctx.writeAndFlush(resp).addListener(ChannelFutureListener.CLOSE);
    }

    static class EchoServerHandler extends ChannelInboundHandlerAdapter {

        // 每当从客户端收到新的数据时，这个方法会在收到消息时被调用
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            ByteBuf inBuffer = (ByteBuf) msg;
            String received = inBuffer.toString(Charset.defaultCharset());
            System.out.println("收到数据：" + received);
            ctx.write(Unpooled.wrappedBuffer("Server message".getBytes()));
            ctx.fireChannelRead(msg);
        }

        /*@Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            if (msg instanceof FullHttpRequest) {
                FullHttpRequest req = (FullHttpRequest) msg;

                // 1.获取URI
                String uri = req.uri();

                ByteBuf byteBuf = req.content();
                String content = byteBuf.toString(CharsetUtil.UTF_8);

                HttpMethod method = req.method();

                HttpHeaders headers = req.headers();

                System.out.printf("uri: %s content: %s method: %s", uri, content, method.toString());
            }
        }*/

        // 数据读取完后被调用
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) {
            ctx.flush();
        }

        // 当Netty由于IO错误或者处理器在处理事件时抛出的异常时被调用
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    }

    public static void main(String[] args) {
        // accept线程组，用来接受连接
        NioEventLoopGroup acceptEventExecutors = new NioEventLoopGroup(1);
        // I/O线程组， 用于处理业务逻辑
        NioEventLoopGroup workerEventExecutors = new NioEventLoopGroup(1);

        // 服务端启动引导
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(acceptEventExecutors, workerEventExecutors) // 绑定两个线程组
                .channel(NioServerSocketChannel.class)  // 指定通道类型
                .localAddress(new InetSocketAddress(7951))
                .option(ChannelOption.SO_BACKLOG, 100) // 设置TCP连接的缓冲区
                .handler(new LoggingHandler(LogLevel.WARN)) // 设置日志级别
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline(); // 获取处理器链
                        pipeline.addLast(new EchoServerHandler()); // 添加新的件处理器
                    }
                });

        try {
            // 通过bind启动服务
            ChannelFuture channelFuture = serverBootstrap.bind().sync();
            // 阻塞主线程，知道网络服务被关闭
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            acceptEventExecutors.shutdownGracefully();
            workerEventExecutors.shutdownGracefully();
        }
    }
}
